package io.r2mo.test.jce;

import io.r2mo.jce.common.HED;
import io.r2mo.jce.component.lic.domain.LicenseConfiguration;
import io.r2mo.jce.component.lic.domain.LicenseData;
import io.r2mo.jce.component.lic.domain.LicenseFile;
import io.r2mo.jce.component.lic.domain.LicensePath;
import io.r2mo.typed.common.Binary;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import java.security.PrivateKey;

/**
 * @author lang : 2025-09-19
 */
@Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LicPureTestCase extends AbstractLicenseTestCase {

    /**
     * 测试：写入新的 License 文件（纯签名版本，无对称加密）
     * <pre>
     * 数据流：
     *   1. 加载原始 JSON -> 转换成 LicenseData（业务实体数据）
     *   2. 动态追加机器指纹（signFinger），用于硬件绑定
     *   3. 构造 LicenseConfiguration（包含 LicenseId、存储路径、公私钥信息）
     *   4. 加载私钥（PrivateKey），用于生成数字签名
     *   5. 调用 service.encrypt(...) -> 得到 LicenseFile（三份内容：.dat / .lic / .sig）
     *   6. 指定格式（TEXT），便于人工查看
     *   7. 调用 io.writeZip(...) -> 打包生成 *.zip（包含三份文件）
     *   8. 将最终 zip 文件写入存储（本地文件系统）
     * </pre>
     */
    @Test
    @Order(1)
    public void writePure() {
        // 📝 Step 1: 打印日志，准备写入新的 License 文件
        log.info("[ R2MOMO ] 写入新的 License！");

        // 📂 Step 2: 从资源目录加载 JSON 数据，反序列化为 LicenseData 对象
        //     - JSON 文件路径: HED/source/license_1.json
        //     - 类型: LicenseData.class
        final LicenseData licenseData = this.inOne("HED/source/license_1.json", LicenseData.class);

        // 🔑 Step 3: 设置硬件指纹（signFinger）
        //     - 使用 HED.fingerHex() 生成 SHA-256 指纹（64 hex）
        //     - 将 License 与具体机器绑定
        licenseData.setSignFinger(HED.fingerHex());

        // 🔎 Step 4: 打印 LicenseData 内容，确认是否加载正确
        log.info("[ R2MOMO ] 读取 License 数据：{}", licenseData);

        // 📦 Step 5: 构造 LicenseConfiguration
        //     - false -> 表示纯签名模式（不需要额外生成对称加密密钥）
        //     - 填充 LicenseId、公私钥路径、元数据等信息
        final LicenseConfiguration licenseConfiguration = this.createConfiguration(false);

        // 📌 Step 6: 打印配置内容，确认路径是否正确
        log.info("[ R2MOMO ] 许可证位置：\n{}", licenseConfiguration);

        // 🔒 Step 7: 从存储中加载私钥
        //     - 路径来源: licenseConfiguration.ioPrivate()
        //     - 用于生成签名（RSA/ECDSA 等）
        final PrivateKey privateKey = store.inPrivate(licenseConfiguration.ioPrivate());

        // ⚙️ Step 8: 使用服务层加密生成 LicenseFile
        //     - 输入：LicenseData + 私钥
        //     - 输出：LicenseFile（包含 data/加密内容/签名）
        //       - data()      -> *.dat 原始 JSON
        //       - encrypted() -> *.lic （这里仍然是纯签名包装，不含对称加密）
        //       - signature() -> *.sig 数字签名文件
        final LicenseFile licenseFile = service.encrypt(licenseData, privateKey);

        // 📝 Step 9: 指定输出格式为 TEXT，便于调试或人工校验
        licenseFile.format(FORMAT);

        // 📦 Step 10: 写入存储
        //     - io.writeZip(...) 会打包 *.dat, *.lic, *.sig -> *.zip
        //     - 返回值 Binary -> 内存中 zip 压缩流
        final Binary in = io.writeZip(licenseFile, licenseConfiguration);

        // 📏 Step 11: 打印最终生成文件的字节长度，确认文件大小合理
        log.info("[ R2MOMO ] 文件尺寸：{}", in.length());

        // 💾 Step 12: 将生成的 zip 文件写入本地存储
        //     - 输出路径: HED/licensing/generated/license_1.zip
        //     - 便于后续分发或上传给客户
        store.write("HED/licensing/generated/license_1.zip", in);
    }

    /**
     * 测试：读取并验证已有的 License 文件（纯签名版本）
     * <pre>
     * 数据流：
     *   1. 加载原始 JSON -> 转换成 LicenseData（业务实体数据）
     *   2. 动态追加机器指纹（signFinger），确保绑定当前硬件
     *   3. 构造 LicenseConfiguration（指定签名模式、公私钥信息、路径配置）
     *   4. 构造 LicensePath，用于定位存储中的 *.dat / *.lic / *.sig
     *   5. 从存储中读取 License 内容（字符串形式）
     *   6. 调用 io.readIn(...) -> 反序列化为 LicenseFile（内存态）
     *   7. 从路径再读取一次 LicenseFile -> 补充元信息
     *   8. 合并 metadata（安全字段、版本、额外信息）
     *   9. 打印 LicenseFile，确认内容
     *  10. 调用 io.verify(...) -> 公钥验签，确认 License 文件未被篡改
     *  11. 返回最终的 LicenseData（业务可用）
     * </pre>
     */
    @Test
    @Order(2)
    public void readLic() {
        log.info("[ R2MOMO ] 读取已有 License！");

        // 📂 Step 1: 从资源目录加载 JSON 数据
        final LicenseData licenseData = this.inOne("HED/source/license_1.json", LicenseData.class);

        // 🔑 Step 2: 设置硬件指纹，确保和写入时一致
        licenseData.setSignFinger(HED.fingerHex());

        // 📦 Step 3: 构造配置，false 表示纯签名模式
        final LicenseConfiguration licenseConfiguration = this.createConfiguration(false);

        // 📌 Step 4: 构造路径对象（包含 dat/lic/sig 的存储路径）
        final LicensePath licensePath = this.createPath(licenseData, FORMAT);

        // 📖 Step 5: 读取 License 文件内容（字符串形式）
        final String content = this.readLic(licenseData, FORMAT, licenseConfiguration);
        log.info("[ R2MOMO ] 许可内容：\n{}", content);

        // 🗂 Step 6: 将字符串反序列化为 LicenseFile
        final LicenseFile licenseFile = io.readIn(content, FORMAT, licenseConfiguration);

        // 🗂 Step 7: 从路径再次读取 LicenseFile，作为安全对照
        final LicenseFile securityFile = io.readIn(licensePath, licenseConfiguration);

        // 🔄 Step 8: 合并元信息（metadata）
        licenseFile.loadMetadata(securityFile);

        // 🔎 Step 9: 打印 LicenseFile 内容
        log.info("[ R2MOMO ] 读取 License 文件：{}", licenseFile);

        // ✅ Step 10: 验签并反序列化，得到最终业务数据
        final LicenseData data = io.verify(licenseFile, licenseConfiguration);
        log.info("[ R2MOMO ] 验证 License 数据：{}", data);
    }
}
